package cn.stalk.wf.component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinitionQuery;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ProcessDefinitionCache implements InitializingBean {

    @Autowired
    private RepositoryService repositoryService;

    private Map<String, ProcessDefinition> cacheWithKey = null;
    private Map<String, ProcessDefinition> cacheWithId = null;

    private Lock lock = new ReentrantLock();

    public ProcessDefinition findByKey(String key) {
        lock.lock();
        try {
            return cacheWithKey.get(key);
        } finally {
            lock.unlock();
        }
    }

    public ProcessDefinition findById(String id) {
        lock.lock();
        try {
            return cacheWithId.get(id);
        } finally {
            lock.unlock();
        }
    }
    
    public Collection<ProcessDefinition> allLatest() {
        lock.lock();
        try {
            return cacheWithKey.values();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        lock.lock();
        try {
            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery().active();
            List<ProcessDefinition> list1 = query.list(); // 全部，含旧流程定义
            List<ProcessDefinition> list2 = query.latestVersion().list(); // 只含最新的流程定义

            cacheWithId = list1.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
            cacheWithKey = list2.stream().collect(Collectors.toMap(e -> e.getKey(), e -> e));
        } finally {
            lock.unlock();
        }
    }

}
